package com.uvnos4j.matilda.system.log;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.uvnos4j.matilda.commons.annotation.AppLog;
import com.uvnos4j.matilda.commons.config.properties.SysProperties;
import com.uvnos4j.matilda.commons.utils.RequestUtil;
import com.uvnos4j.matilda.commons.utils.UserUtil;
import com.uvnos4j.matilda.system.domain.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 统一处理web请求日志的切面
 *
 * @author Guo.wl
 */
@Slf4j
@Aspect
@Component
public class AppLogAspect {
    @Autowired
    private SysProperties sysProperties;

    /**
     * 将ErrorStack转化为String.
     */
    private static String getStackTraceAsString(Throwable e) {
        if (e == null) {
            return "";
        }
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }

    @Pointcut("@annotation(com.uvnos4j.matilda.commons.annotation.AppLog)")
    public void appLog() {
    }

    @Around("appLog()")
    public Object saveSysLog(ProceedingJoinPoint pjp) {
        // 前置通知
        HttpServletRequest request = RequestUtil.getHttpServletRequest();

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        String methodName = signature.getName();
        Method method = signature.getMethod();
        Object result;
        try {
            // 执行目标方法
            result = pjp.proceed();
            // 后置通知
            accessLog(method, request, null);
        } catch (Throwable e) {
            // 异常通知
            accessLog(method, request, e);
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 保存日志
     */
    private void accessLog(Method method, HttpServletRequest request, Throwable e) {
        if (!sysProperties.isSaveLogToDb()) {
            return;
        }

        String username = UserUtil.getUsername();
        if (StrUtil.isBlank(username)) {
            return;
        }

        boolean flag = method.isAnnotationPresent(AppLog.class);
        if (!flag) {
            return;
        }
        // 存在WebLog注解的进行通用权限记录
        AppLog appLog = method.getAnnotation(AppLog.class);
        SysLog log = new SysLog();
        // 日志类型（1：接入日志；2：错误日志）
        log.setType(e == null ? "接入日志" : "错误日志");
        log.setTitle(appLog.title());
        log.setCreateBy(username);
        log.setCreateDate(LocalDateTime.now());
        log.setRemoteAddr(request.getRemoteAddr());
        log.setUserAgent(request.getHeader("user-agent"));
        log.setRequestUri(request.getRequestURI());
        log.setMethod(request.getMethod());
        log.setParams(JSONUtil.toJsonStr(request.getParameterMap()));
        log.setException(getStackTraceAsString(e));

        ThreadUtil.execute(new SaveLogRunnable(log));

    }

}
